#include<iostream>

#include<stdio.h>

#include<vector>

#include<unistd.h>

#include<stdlib.h>

#include<string>

#include<time.h>

#include <sys/types.h>

#include <sys/wait.h>

#define N 5

#define SIZE 1024

typedef void(*task_t)();

std::vector<task_t> tasks;

void task1()
{
    std::cout << "执行任务一" << std::endl;
}

void task2()
{
    std::cout << "执行任务二" << std::endl;
}

void task3()
{
    std::cout << "执行任务三" << std::endl;
}

void task4()
{
    std::cout << "执行任务四" << std::endl;
}

void LoadTask(std::vector<task_t> *tasks)
{
    tasks->push_back(task1);
    tasks->push_back(task2);
    tasks->push_back(task3);
    tasks->push_back(task4);
}

class channel
{
public:
    channel(int a, pid_t b, const std::string& c):
        _cmd_fd(a),
        _slaverid(b),
        _processname(c)
    {
    }

    int _cmd_fd;
    pid_t _slaverid;
    std::string _processname;
};



void PP_Slaver(int n)
{
    int get = 0;
    while(1)
    {
        ssize_t ret = read(0, &get, sizeof(get));
        if(ret > 0)
        {
            std::cout << "process-" << n << "得到一个任务：" << get << std::endl;
            if(get >= 0 && get < tasks.size()) tasks[get]();
        }
        else if(ret == 0)
        {
            std::cout << "父进程关闭管道，子进程退出。" << std::endl;
            close(0);
            break;
        }
        else
        {
            std::cout << "process-" << n << "的";
            perror("read");
            break;
        }
    }
}

void PP_Init(std::vector<channel>& ch)
{
    for(int i = 0; i < N; ++i)
    {
        int ret_fd[2] = {0};
        int back = pipe(ret_fd);
        if(back < 0)
        {
            perror("pipe");
            exit(1);
        }
        pid_t ret = fork();
        if(ret == 0)
        {
            close(ret_fd[1]);
            dup2(ret_fd[0], 0);
            close(ret_fd[0]);
            PP_Slaver(i);

            // std::cout << "process-" << i << "quit" << std::endl;
            exit(0);
        }
        else if(ret > 0)
        {
            close(ret_fd[0]);
            std::string tmp("process-");
            tmp += std::to_string(i);
            ch.push_back(channel(ret_fd[1], ret, tmp));
            std::cout << ret_fd[1];
            std::cout << tmp << " 创建成功" << std::endl;
        }
        else
        {
            perror("fork");
            exit(1);
        }
    }
}

void PP_Menu()
{
    std::cout << "#################################################" << std::endl;
    std::cout << "# 1.任务一                 2.任务二             #" << std::endl;
    std::cout << "# 3.任务三                 4.任务四             #" << std::endl;
    std::cout << "#                          0.退出               #" << std::endl;
    std::cout << "#################################################" << std::endl;
}

void PP_CtrlSlaver(const std::vector<channel> &ch)
{
    int choose = 0;
    while(true)
    {
        PP_Menu();
        int in = 0;
        std::cin >> in;
        if(in == 0) 
        {
            // std::cout << in << std::endl;
            break;
        }

        write(ch[choose]._cmd_fd, &in, sizeof(in));

        ++choose;
        choose %= N;
        sleep(1);
    }
}

void PP_Quit(const std::vector<channel> &ch)
{
    for(int i = ch.size() - 1; i >= 0; --i)
    {
        close(ch[i]._cmd_fd);
        int st = 0;
        waitpid(ch[i]._slaverid, &st, 0);
        if(WIFEXITED(st))
        {
            std::cout << "子进程正常退出，退出状态：" << WEXITSTATUS(st) << std::endl;
        }
        else
        {
            std::cout << "子进程异常退出，异常信号：" << WTERMSIG(st) << std::endl;
        }
    }
}

int main()
{
    LoadTask(&tasks);

    srand(time(nullptr));

    std::vector<channel> channels;

    PP_Init(channels); // 初始化

    PP_CtrlSlaver(channels); // 选择

    // std::cout << 666 << std::endl;

    PP_Quit(channels); // 进程退出

    return 0;
}
